home *** CD-ROM | disk | FTP | other *** search
/ Fritz: All Fritz / All Fritz.zip / All Fritz / FILES / PROGNG_C / TURBOCU2.LZH / INDEX.ARC / INDEX.DOC < prev    next >
Text File  |  1987-08-21  |  22KB  |  553 lines

  1. .PL
  2.  
  3.  
  4. INDEX.DOC                   Version 1.01                   August 21, 1987
  5.                                                                    Page 1
  6.  
  7. This documentation and the software it describes are Copyright 1987, Jim 
  8. Mischel.  You are free to use this software providing that the following 
  9. conditions are met:
  10.  
  11.      1)  Any distributed versions contain the my copyright notice and are 
  12.          accompanied by documentation and source code.  The package doesn't do 
  13.          anybody any good if they don't know how to use it.
  14.      2)  You notify me before using it in any commercial application.  I won't 
  15.          ask for any money, I'd just like to know about it.  Also, if you 
  16.          notify me I may be able to get you a current version and/or notify 
  17.          you of any bug fixes.
  18.  
  19. This package was developed using Turbo C version 1.0.  It should port to other 
  20. compilers and operating systems with very little modification.
  21.  
  22. Questions, comments, problems should be addressed to Jim Mischel, CIS id 
  23. number 73717,1355.  I regularly visit BORPRO, CLMFORUM, and DDJFORUM.  I'd be 
  24. more than happy to reply to inquiries.
  25.  
  26.  
  27. INDEX.DOC                   Version 1.01                   August 21, 1987
  28.                                                                    Page 2
  29. DESCRIPTION
  30.  
  31. INDEX is a collection of routines designed to provide single-key indexed file 
  32. access to C programs.  They are modeled after the ISAM features supplied in 
  33. standard COBOL implementations, with some additions.  Keys can be of any type, 
  34. including float, double, and user-defined key types.
  35.  
  36. This version of the package uses a threaded binary tree to maintain the index.  
  37. This may change in future versions.  I chose the threaded tree because it is 
  38. relatively simple to implement, uses little memory, and is acceptable for 
  39. small and medium-sized data sets.  It is not the fastest method available, and 
  40. I make no claims as to the speed of record access, though it should be 
  41. acceptable.  Currently, no balancing is performed when adding or deleting 
  42. records from the file.  In many cases, this can result in a severely un-
  43. balanced tree and horribly slow access times.  I am currently working on 
  44. adding the tree balancing routines.
  45.  
  46. Following are descriptions of the user-accessable routines.  These are the 
  47. only routines that should be called by applications programs.  Calling other 
  48. routines in the package will produce unpredictable results and could very 
  49. possibly destroy the database.
  50.  
  51. The examples provided build on previous examples.  For example, the example 
  52. used with iclose() uses data types defined in the example provided with 
  53. iopen().
  54.  
  55.  
  56. INDEX.DOC                   Version 1.01                   August 21, 1987
  57.                                                                    Page 3
  58. IOPEN - open a file for indexed I/O
  59.  
  60. void *iopen(char *fname, unsigned recsiz, char keytyp, unsigned offset,
  61.             char dupflag, int (*cmp_rtn)());
  62.  
  63. iopen opens an indexed file for reading/writing.  If the file to be opened 
  64. does not exist, iopen attempts to create it.  Upon successful completion, 
  65. iopen will return a pointer to an index control record.  This pointer should 
  66. not be modified by the application program, nor should the fields in the index 
  67. control record be changed by the application.  The data in the record is used 
  68. by the index routines and is at best marginally useful to the application.  
  69. Modifying either the returned pointer or the data pointed to will produce 
  70. unpredictable results and could very likely make the database unuseable.  If 
  71. iopen can not open the file, NULL is returned and the global variable ierrno 
  72. is set to identify the cause of the error. 
  73.  
  74. Arguments passed to iopen()
  75.  
  76. fname          A string containing the name of the file to be opened.  This 
  77.                name should be without an extension.  iopen will append the 
  78.                extension '.DAT' for the data file and the extension '.INX' for 
  79.                the index file.
  80.  
  81. recsiz         Size of the data record in characters.
  82.  
  83. keytyp         The type of key.  Standard key types supplied in the header 
  84.                file, INDEX.H are:
  85.  
  86.                UCHAR   unsigned character key
  87.                SCHAR   signed character key
  88.                UINT    unsigned int key
  89.                SINT    signed int key
  90.                ULONG   unsigned long key
  91.                SLONG   signed long key
  92.                STRING  string key (ASCIIZ)
  93.                FLOAT   float key
  94.                DOUBLE  double key
  95.  
  96.                The last two key types (FLOAT and DOUBLE) are available only if 
  97.                INDEX.C was compiled with the FLOAT_KEY option.  This prevents 
  98.                the floating point libraries from being included unless they 
  99.                are needed.
  100.  
  101.                If the key for this file is not one of the above types, use 0 
  102.                for keytyp and pass the name of the key comparison routine in 
  103.                the cmp_rtn field.
  104.  
  105. offset         The offset (in characters) from the beginning of the record to 
  106.                the first byte of the key.
  107.  
  108. dupflag        Controls whether duplicate keys are allowed.  If dupflag is 0, 
  109.                duplicate keys are not allowed, and an attempt to add a 
  110.                duplicate key will return an error (see error codes below).  If 
  111.                dupflag is 1, duplicate keys will be allowed.
  112.  
  113.  
  114. INDEX.DOC                   Version 1.01                   August 21, 1987
  115.                                                                    Page 4
  116. IOPEN - open a file for indexed I/O
  117.  
  118. cmp_rtn        Is a pointer to a user-defined key comparison routine.  If the 
  119.                key is one of the standard key types, this field should be 
  120.                NULL.  If this field is not NULL, iopen will use this as a 
  121.                pointer to a user-defined key comparison routine.  The 
  122.                declaration of the routine should be:
  123.  
  124.                int routine_name(void *arg1, void *arg2);
  125.  
  126.                This routine accepts pointers to the operands and returns
  127.                   -1 if arg1 < arg2
  128.                    0 if arg1 == arg2
  129.                    1 if arg1 > arg2
  130.  
  131. Example:
  132.  
  133. #include <stdio.h>
  134. #include "index.h"
  135.  
  136. main (int argc, char *argv[]) {
  137.  
  138. struct {
  139.   char first_name[25],
  140.        last_name[25];
  141. } name_rec;
  142.  
  143. char *name_file;         /* pointer to control record */
  144. unsigned offset;
  145.  
  146. offset = &name_rec.last_name - &name_rec;    /* compute key offset */
  147. if ((name_file = iopen(argv[1],sizeof(name_rec),STRING,offset,1,NULL) == NULL) 
  148.   {
  149.     printf("Error opening file %s\n",argv[1]);
  150.     printf("Error code is %X\n",ierrno);
  151.     return;
  152.   }
  153.  
  154.  
  155. INDEX.DOC                   Version 1.01                   August 21, 1987
  156.                                                                    Page 5
  157. ICLOSE - close files and free memory
  158.  
  159. void iclose(void *db_control);
  160.  
  161. iclose closes the index and data files assigned to the index control record, 
  162. and frees the memory used.  iclose does not return status.
  163.  
  164. IMPORTANT NOTE:
  165. All files opened with iopen that have had records added or deleted MUST be 
  166. closed with iclose.  Failure to do so may result in losing data or destroying 
  167. the integrity of the index file.
  168.  
  169. Arguments passed to iclose()
  170.  
  171. db_control     The pointer returned when the file was opened by iopen.
  172.  
  173.  
  174. Example: (building on the one above)
  175.  
  176.   iclose(name_file);
  177.  
  178.  
  179. INDEX.DOC                   Version 1.01                   August 21, 1987
  180.                                                                    Page 6
  181. IREAD - read a record from the file
  182.  
  183. int iread(void *db_control, void *destin);
  184.  
  185. iread reads a record and places it in memory at destin.  iread assumes there 
  186. is sufficient space at destin to hold the entire data record.  Place the key 
  187. value to be searched for at the key position in the record at destin and call 
  188. iread.  iread returns 0 if the record was found, I_NOREC if not, and error 
  189. status if there was an I/O error.  On error conditions, the data at destin is 
  190. not changed.  Using iread does not change the pointer used by the sequential 
  191. read functions iread_next and iread_prev.
  192.  
  193. Arguments passed to iread()
  194.  
  195. db_control     The pointer returned when the file was opened by iopen.
  196.  
  197. destin         A pointer to the structure that will receive the data record.
  198.  
  199. Example:
  200.  
  201.   name_rec.last_name = "Mischel";
  202.   if (iread(name_file,&name_rec)) {
  203.     printf("\007Record key %s not found in file %s\n",
  204.             name_rec.last_name,argv[1]);
  205.     printf("Error code is %X\n",ierrno);
  206.   }
  207.   else
  208.     printf("Record found\n");
  209.  
  210.  
  211. INDEX.DOC                   Version 1.01                   August 21, 1987
  212.                                                                    Page 7
  213. ISTART - position file for sequential access
  214.  
  215. int istart(void *db_control, char cond, void *source);
  216.  
  217. istart positions the file pointer for sequential file access.  This function 
  218. must be called before attempting to sequentially access the file through 
  219. iread_next or iread_prev.  Place the key value to be searched for at the key 
  220. position in source and call istart.  No data is transferred by this function.
  221. istart will return 0 if the file pointer was positioned successfully, EOF if 
  222. no record meeting key and cond could be found, and one of the standard error 
  223. codes on error.
  224.  
  225. Arguments passed to istart()
  226.  
  227. db_control     The pointer returned when the file was opened by iopen.
  228.  
  229. cond           One of the conditions defined in INDEX.H:
  230.  
  231.                START_FILE     Start at beginning of file, source is ignored
  232.                LT             Start at the key less than the key in source
  233.                LE             Start at key less then or equal to key in 
  234.                               source.  If a record exists with key, it will 
  235.                               start there.
  236.                EQ             Start at key equal to the key in source.
  237.                GE             Start at key greater than or equal to key in 
  238.                               source.  If a record exists with key, it will 
  239.                               start there.
  240.                GT             Start at key greater than key in source.
  241.                END_FILE       Start at end of file.  This is useful for 
  242.                               reading the entire file backwards.
  243.  
  244. Example:
  245.  
  246. /*
  247.  * to position the file at the first record with a key greater than or equal
  248.  * to Sm.
  249.  */
  250.   name_rec.last_name = "Sm";
  251.   if (istart(db_control,GE,&name_rec)) {
  252.     printf("Couldn't position file\n");
  253.     printf("Error code is %X\n",ierrno);
  254.   }
  255.   else {
  256.   /*
  257.    * read the file sequentially forward or backward.  See examples for
  258.    * iread_next and iread_prev.
  259.    */
  260.   }
  261.  
  262.  
  263. INDEX.DOC                   Version 1.01                   August 21, 1987
  264.                                                                    Page 8
  265. IREAD_NEXT - Sequentially read the next record
  266.  
  267. int iread_next(void *db_control, void *destin);
  268.  
  269. Read the next record in sequence into destin.  iread_next assumes there is 
  270. room in destin for the entire record.  Returns 0 if successful, EOF at end of 
  271. file, standard error code on error.  On error conditions, the data at destin 
  272. is not changed.
  273.  
  274. Arguments passed to iread_next()
  275.  
  276. db_control     The pointer returned when the file was opened by iopen.
  277.  
  278. destin         A pointer to the structure to receive the data record.
  279.  
  280. Example:
  281.  
  282.   /*
  283.    * read the file sequentially forward (assuming it was started as above)
  284.    */
  285.     while (!iread_next(db_control,&name_rec))
  286.       printf("%s %s\n",name_rec.first_name,name_rec.last_name);
  287.  
  288.  
  289. INDEX.DOC                   Version 1.01                   August 21, 1987
  290.                                                                    Page 9
  291. IREAD_PREV - sequentially read the previous record
  292.  
  293. int iread_prev(void *db_control, void *destin);
  294.  
  295. read the previous record in sequence into destin.  Assumes there is room in 
  296. destin for the entire record.  Returns 0 if successful, EOF at top of file, 
  297. standard error code on error.  On error conditions, the data at destin is not 
  298. changed.
  299.  
  300. Arguments passed to iread_prev()
  301.  
  302. db_control     The pointer returned when the file was opened by iopen.
  303.  
  304. destin         A pointer to the structure to receive the data record.
  305.  
  306. Example:
  307.  
  308.   /*
  309.    * read the file sequentially backward (assuming it was started as above)
  310.    */
  311.     while (!iread_prev(db_control,&name_rec))
  312.       printf("%s %s\n",name_rec.first_name,name_rec.last_name);
  313.  
  314.  
  315. INDEX.DOC                   Version 1.01                   August 21, 1987
  316.                                                                    Page 10
  317. IWRITE - add a new record
  318.  
  319. int iwrite(void *db_control, void *source);
  320.  
  321. Write the record from source to the data file.  Data records are always added 
  322. to the end of the file.  Returns 0 if successful, I_INVKEY if duplicates are 
  323. not permitted and an attempt was made to add a duplicate record, standard 
  324. error code otherwise.
  325.  
  326. Arguments passed to iwrite()
  327.  
  328. db_control     The pointer returned when the file was opened by iopen.
  329.  
  330. source         A pointer to the structure to be written.
  331.  
  332. Example:
  333.  
  334.   name_rec.first_name = "Jim";
  335.   name_rec.last_name = "Mischel";
  336.   switch (iwrite(db_control,&name_rec)) {
  337.     case 0        :
  338.       printf("Record written\n");
  339.       break;
  340.     case I_INVKEY :
  341.       printf("Duplicate key %s\n",name_rec.last_name);
  342.       break;
  343.     default       :
  344.       printf("Write error.  Error code is %X\n",ierrno);
  345.   }
  346.  
  347.  
  348. INDEX.DOC                   Version 1.01                   August 21, 1987
  349.                                                                    Page 11
  350. IREWRITE - update an existing record
  351.  
  352. int irewrite(void *db_control, void *source);
  353.  
  354. Update the current record in the file.  The record must have been read using 
  355. one of the read routines, or written using iwrite, and must still be in the 
  356. buffer.  It is not possible to change the key using irewrite.  Use idelete to 
  357. remove the record and iwrite to add the record after the key has been changed.
  358. Returns 0 on success, I_INVKEY if attempt to rewrite a record that isn't in 
  359. the buffer, standard error code otherwise.
  360.  
  361. Arguments passed to irewrite()
  362.  
  363. db_control     The pointer returned when the file was opened by iopen.
  364.  
  365. source         A pointer to the structure to be written.
  366.  
  367. Example:
  368.  
  369.   /* first we have to read the record */
  370.   name_rec.last_name = "Smith";
  371.   if (iread(name_file,&name_rec)) {
  372.     printf("\007Record key %s not found in file %s\n",
  373.             name_rec.last_name,argv[1]);
  374.     printf("Error code is %X\n",ierrno);
  375.   }
  376.   else {
  377.     name_rec.first_name = "John";
  378.     switch (irewrite(db_control,&name_rec)) {
  379.       case 0 :
  380.         printf("Success\n");
  381.         break;
  382.       case I_INVKEY :
  383.         printf("Invalid rewrite attempted\n");
  384.         break;
  385.       default :
  386.         printf("Rewrite error.  Error code is %X\n",ierrno);
  387.     }
  388.  
  389.  
  390. INDEX.DOC                   Version 1.01                   August 21, 1987
  391.                                                                    Page 12
  392. IDELETE - delete a record
  393.  
  394. int idelete(void *d, void *source);
  395.  
  396. Delete the record currently in the buffer.  Record must have been read using 
  397. one of the read routines, or written using iwrite, and still be in the buffer.  
  398. Returns 0 on success, I_INVKEY if attempt to delete a record that isn't in the 
  399. buffer, standard error code otherwise.
  400.  
  401. When a record is deleted, it is not removed from the data file and its index 
  402. pointer is not removed from the index file.  What happens is that the index 
  403. pointers are re-arranged to point past the deleted record.  This has at least 
  404. two major side affects:
  405.   1)  If the data file is scanned by a program that doesn't use the index 
  406.       routines, deleted records will be picked up along with current records.
  407.   2)  In a file that has a large turnover rate, there will be a considerable 
  408.       amount of wasted space taken up by the deleted records.
  409. The next version of the package will include a rebuild() function that will, 
  410. among other things, remove deleted records from a data file.  This program 
  411. will fix the second problem.  The first problem can be solved in one of two 
  412. ways:
  413.   1)  Add a flag to the data record to indicate it is deleted.  Your program 
  414.       will have to manipulate this flag, setting it before the record is 
  415.       deleted.
  416.   2)  Wait for the next version of the package.  By using the rebuild() 
  417.       function before scanning the file, you're guaranteed not to have any 
  418.       deleted records.
  419.  
  420. Arguments passed to idelete()
  421.  
  422. db_control     The pointer returned when the file was opened by iopen.
  423.  
  424. source         A pointer to the structure containing the key name to be 
  425.                deleted.
  426.  
  427.  
  428. INDEX.DOC                   Version 1.01                   August 21, 1987
  429.                                                                    Page 13
  430. IDELETE - delete a record
  431.  
  432. Example:
  433.  
  434.   /* first read the record */
  435.   name_rec.last_name = "Smith";
  436.   if (iread(name_file,&name_rec)) {
  437.     printf("\007Record key %s not found in file %s\n",
  438.             name_rec.last_name,argv[1]);
  439.     printf("Error code is %X\n",ierrno);
  440.   }
  441.   else {
  442.     switch (idelete(db_control,&name_rec)) {
  443.       case 0 :
  444.         printf("Record deleted\n");
  445.         break;
  446.       case I_INVKEY :
  447.         printf("Invalid delete attempted\n");
  448.         break;
  449.       default :
  450.         printf("Delete error.  Error code is %X\n",ierrno);
  451.     }
  452.  
  453.  
  454. INDEX.DOC                   Version 1.01                   August 21, 1987
  455.                                                                    Page 14
  456. ERROR CODES
  457.  
  458. The global variable ierrno will contain the results of the last I/O operation.  
  459. Possible values are:
  460.  
  461. Code      Value  Description
  462. ----      -----  -----------
  463. I_NODAT   0x10 - couldn't open data file (iopen)
  464. I_DATRD   0x11 - I/O error attempting to read data file (any)
  465. I_DATWT   0x12 - I/O error attempting to write to data file (any)
  466. I_NOINX   0x20 - couldn't open index file (iopen)
  467. I_INXRD   0x21 - I/O error attempting to read index file (any)
  468. I_INXWT   0x22 - I/O error attempting to write to index file (any)
  469. I_INVKEY  0x80 - Attempt to add duplicate key (iwrite)
  470.                  Attempt to rewrite deleted record, or record not in buffer
  471.                  (irewrite)
  472.                  Attempt to delete deleted record, or record not in buffer
  473.                  (idelete)
  474. I_NOMEM   0x81 - out of memory (iopen)
  475. I_NOREC   0x82 - record not found (iread)
  476.  
  477.  
  478. INDEX.DOC                   Version 1.01                   August 21, 1987
  479.                                                                    Page 15
  480. NOTES
  481.  
  482. I have included a sample program that illustrates the use of several of the 
  483. routines in this package.  The program, ADR.C, is a simple address/phone book 
  484. that is marginally useful as a real application, but does show how to use the 
  485. routines.
  486.  
  487. MAKE FILE
  488. I have included a make file that can be used to re-compile the package.  This 
  489. file uses the QLIB program to create the library INDEX.LIB.  The QLIB program 
  490. is available on BORPRO DL 11.  The library supplied with the package is a 
  491. TLINK compatible library and is not compatible with Microsoft's LINK.  
  492.  
  493. KNOWN BUGS
  494.  
  495. There are some possible conflicts when using sequential and random I/O at the 
  496. same time.  These will only occur when adding or deleting records while 
  497. sequentially scanning the file.  In general, the only problems involve 
  498. deleting a record that is to be the next one read, or adding a record between 
  499. the current and next records.  In the delete case, the deleted record will 
  500. still be read, and in the add case, the new record will not be read.  The next 
  501. release should fix these problems.
  502.  
  503. REVISION HISTORY
  504.  
  505. This package started as a "I wonder how that's done" type of project.  The 
  506. original program used a primitive hashing algorithm to store and retrieve the 
  507. keys.  The program (written in Pascal) did work, but was a terrible kludge and 
  508. I threw it away.  The current version was written for two reasons:  1)  I 
  509. wanted to learn C, and 2)  I needed something like this for a project I was 
  510. planning.
  511.  
  512. Version 1.00  August 13, 1987
  513. Original release version.
  514.  
  515. Version 1.01  August 21, 1987
  516.      1) Fixed bugs in iwrite() and irewrite() that prevented the data buffer 
  517.         from being updated when the record was written.  This bug caused 
  518.         irewrite() and idelete() to erroneously return I_INVKEY.
  519.      2) Updated documentation.  Added examples and cleaned things up quite a 
  520.         bit.
  521.      3) Split the package into multiple source files and added a make file 
  522.         that creates a Turbo C compatible library.
  523.      4) Add calls to fflush() in the write routines.  This slows things down a 
  524.         bit (a lot?), but does help keep data file integrity.
  525.  
  526.  
  527. INDEX.DOC                   Version 1.01                   August 21, 1987
  528.                                                                    Page 16
  529. NOTES
  530.  
  531. Files that make up the index package
  532.  
  533. ADR.C     - demonstration program for index package
  534. ADR.MAK   - make file for ADR
  535. ADR.PRJ   - project file for ADR
  536. ARCIT.BAT - batch file to build the archive
  537. IDELETE.C - delete record routine
  538. INAMES    - name file for QLIB program
  539. INXRTNS.C - support functions for index package
  540. INDEX.DOC - index documentation, rough but useable
  541. INDEX.H   - header file included by application programs
  542. INDEX.LIB - index routines library (useable only by TLINK, not by MS LINK)
  543. INDEX.MAK - make file for index routines
  544. INXDEFS.H - header file for index routines
  545. IOPEN.C   - open and close functions
  546. IREADN.C  - readnext function
  547. IREADP.C  - readprevious function
  548. IREADR.C  - read random function
  549. IREWRITE.C- rewrite (update) record function
  550. ISTART.C  - start function
  551. IWRITE.C  - write record function
  552. Aî